`include "timescale.v"

module ahb_ctrl(
	input 		   hresetn,
	input 		   hclk,
	
	output reg [31:0]  haddr,
	output reg [1:0]   htrans,
	output reg 		   hwrite,
	output reg [2:0]   hsize,
	output reg [2:0]   hburst,
	output reg [3:0]   hprot,
	output reg [31:0]  hwdata,

	// output 		   hsel,

	input  [1:0]   hresp,
	input  [31:0]  hrdata, 

	input  [31:0]  tx_bd_pointer,		//the apb register's output 
	input 		   LatchTx		//the start signal
	
);

// reg 			  start;
reg 	  [31:0]  TxBDConfig, TxBDAddr;
wire 			  StartIdle, StartReqBus, StartReadBD, StartReadFrame;
reg 			  StateIdle, StateReqBus, StateReadBD, StateReadFrame;

wire 	  [10:0]  TxFrameLen;
assign 			  TxFrameLen  = TxBDConfig[10:0];

// ==================== counter ====================
reg 	  [10:0]  WordCnt;				//max 2048
wire 			  ResetWordCnt, IncrementWordCnt;
assign 			  ResetWordCnt = StartReadBD | StartReadFrame;
assign 			  IncrementWordCnt = ~ResetWordCnt & (StateReadBD | StateReadFrame) ;
always@(posedge hclk or negedge hresetn)
begin
  if(!hresetn)
	WordCnt <= 11'd0;
  else if(ResetWordCnt)
	WordCnt <= 11'd0;
  else if(IncrementWordCnt)
	WordCnt <= WordCnt + 11'd1;
end

wire 			  WordCntEq2;
assign 			  WordCntEq2  = WordCnt[1:0] == 2'd2;

wire 			  ReadFrameFinish;
assign 			  ReadFrameFinish = WordCnt == TxFrameLen;


// -------------------- DMA ctrl fsm --------------------
assign 			  StartIdle   = StateReadFrame & ReadFrameFinish;
assign 			  StartReqBus = StateIdle & LatchTx;
assign 			  StartReadBD = StateReqBus & 1;
assign 			  StartReadFrame = StateReadBD & WordCntEq2;

always@(posedge hclk or negedge hresetn)
begin
  if(!hresetn) begin
	StateIdle <= 1'b1;
	StateReqBus <= 1'b0;
	StateReadBD <= 1'b0;
	StateReadFrame <= 1'b0;
  end
  else begin
	if(StartReqBus)
	  StateIdle <= 1'b0;
	else if(StartIdle)
	begin
	  StateIdle <= 1'b1;
	end

	if(StartReadBD)
	  StateReqBus <= 1'b0;
	else if(StartReqBus)
	begin
	  StateReqBus <= 1'b1;
	end

	if(StartReadFrame)
	  StateReadBD <= 1'b0;
	else if(StartReadBD)
	begin
	  StateReadBD <= 1'b1;
	  
	end
	
	if(StartIdle)
	  StateReadFrame <= 1'b0;
	else if(StartReadFrame)
	  StateReadFrame <= 1'b1;
  end
end
//////////////////// end of DMA ctrl fsm ////////////////////


////////////////////////////////////////

always@(posedge hclk)
begin
  if(StartReadBD)
  begin
	//now start reading data
	haddr <= {tx_bd_pointer[31:10], tx_bd_pointer[9:3], 3'b000};
	htrans <= 2'b10;
	hwrite <= 1'b0;
	hsize <= 3'b010;	//word
	hburst <= 3'b000;
	hprot <= 4'b0000;
	hwdata <= 32'hx;
  end
  else if(StateReadBD)
  begin
	if(WordCnt == 0) begin
	  haddr <= {tx_bd_pointer[31:10], tx_bd_pointer[9:3]+4, 3'b000};	//or set the hburst as INCR ??
	end
	else if(WordCnt == 1) begin
	  TxBDConfig <= hrdata;
	  //check the bd is enabled or not ?? get the length here ?

	  //insert an idle clk ???
	  htrans <= 2'b00;			//IDLE, the RAM should ignore this transmission
	end
	else if(WordCnt == 2) begin
	  TxBDAddr <= hrdata + 32'd4;
	  //start read the data from buffer
	  haddr <= hrdata;
	end
  end 
  else if(StateReadFrame)
  begin
	begin
	  haddr <= TxBDAddr;
	  TxBDAddr <= TxBDAddr + 32'd4;
	end
  end
end

endmodule // ahb_ctrl


// ram_top U_ram(
// 		.hclk(hclk)                ,
// 		.hresetn(hresetn)             ,
// 		.hsel_s(hsel)              ,
// 		.haddr_s(haddr[19:0])             ,
// 		.hburst_s(hburst)            ,
// 		.htrans_s(htrans)            ,
// 		.hrdata_s(hrdata)            ,
// 		.hwdata_s(hwdata)            ,
// 		.hwrite_s(hwrite)            ,
// 		.hready_s(hready)            ,
// 		.hresp_s			(hresp)
// 		);


// initial begin
//   hresetn = 0;
//   #10 hresetn = 1;
// end

// initial begin
//   hclk = 0;
//   forever #5 hclk = ~hclk;
// end

// initial begin
//   hsel = 0;

//   #20;
//   @(posedge hclk);
//   hsel = 1;
//   hburst = 3'b000;
//   htrans = 2'b10;
//   hwrite = 1;
//   haddr = 32'h0000_0010;
//   hwdata = 32'h1234_5678;

//   @(posedge hclk);
//   haddr = 32'h0000_0011;
//   hwdata = 32'h1234_5679;

//   @(posedge hclk);
//   haddr = 32'h0000_0012;
//   hwdata = 32'h1234_567a;

//   @(posedge hclk);
//   haddr = 32'h0000_0013;
//   hwdata = 32'h1234_567b;

//   @(posedge hclk);
//   haddr = 32'h0000_0014;
//   hwdata = 32'h1234_567c;
  
// end

// endmodule // ahb_master


// always@(posedge hclk or negedge hresetn)
// begin
//   if(!hresetn) begin
// 	// ...
// 	end
//   else begin
	
// 	if(start) begin
// 	  haddr <= ;

// 	  // hwdata <= ;
// 	  hready <= ;
// 	  hrdata <= ;
// 	end

	
//   end
	
	
// end



// wire 	  [31:0]  BASE_ADDR;
// assign 			  BASE_ADDR   = 32'h8001_0000;

// // reg 	  [31:0]  rx_bd, tx_bd;
// // reg 	  [31:0]  rx_bd, tx_bd;
// reg 	  [31:0]  DMA_CTRL[0:7];				//8 words memory
// // 0 : tx_bd
// // 1 : rx_bd


// //fsm of the write operation
// localparam [1:0]  IDLE 		  = 2'b00,
// 				  SETUP = 2'b01,
// 				  ENABLE = 2'b11;

// reg 	  [1:0]   currentState, nextState;
// always@(*)
// begin
//   nextState = IDLE;
//   case(currentState)
// 	  IDLE: begin
// 		if(psel & ~penable)
// 		  nextState = SETUP;
// 	  end
// 	  SETUP: begin
// 		if(psel & penable)
// 		  nextState = ENABLE;	//the next clk must go into this state
// 	  end
// 	  ENABLE: begin
// 		if(psel & ~penable)
// 		  nextState = SETUP;
// 	  end
//   endcase
// end


// reg 	  [31:0]  waddr;
// integer 		  i;
// always@(posedge pclk or negedge presetn)
// begin
//   if(!presetn) begin
// 	currentState <= IDLE;
// 	for(i=0;i<8;i=i+1)
// 	  DMA_CTRL[i] <= 32'd0;
//   end
//   else begin
// 	currentState <= nextState;
// 	case(nextState)
// 		SETUP: begin
// 		  $display("paddr = %x", paddr);
// 		  waddr <= paddr;
// 		end
// 		ENABLE:
// 		  DMA_CTRL[waddr-BASE_ADDR] <= pwdata;
// 	endcase
//   end
// end

// endmodule // apb


// // always@(posedge pclk or negedge presetn)
// // begin
// //   if(!presetn) begin
// // 	rx_bd <= 32'h0000_0000;				//the init value ??
// // 	tx_bd <= 32'h0000_0000;
// //   end
// //   else 
// // 	case(currentState)
// // 		end
// // end

